﻿using AutoMapper;
using AutoMapper.QueryableExtensions;
using MediatR;
using Microsoft.EntityFrameworkCore;
using WeatherHistory.Data.Repositories.Interfaces;
using WeatherHistory.Shared.Exceptions;

namespace WeatherHistory.Api.CommandsQueries.Queries.Weathers.Search;

public class SearchWeathersQueryHandler : IRequestHandler<SearchWeathersQueryRequest, SearchWeathersQueryResponse>
{
    private readonly IMapper _mapper;
    private readonly IRegionRepository _regionRepository;
    private readonly IWeatherRegionRelationRepository _weatherRegionRelationRepository;

    public SearchWeathersQueryHandler(IMapper mapper, IWeatherRegionRelationRepository weatherRegionRelationRepository, IRegionRepository regionRepository)
    {
        _mapper = mapper;
        _weatherRegionRelationRepository = weatherRegionRelationRepository;
        _regionRepository = regionRepository;
    }

    public async Task<SearchWeathersQueryResponse> Handle(SearchWeathersQueryRequest request, CancellationToken cancellationToken)
    {
        var response = new SearchWeathersQueryResponse();

        var weatherRegionRelationsQuery = _weatherRegionRelationRepository.AsQueryable();

        if (request.StartDateTime.HasValue) weatherRegionRelationsQuery = weatherRegionRelationsQuery.Where(x => x.Weather.MeasurementDateTime >= request.StartDateTime.Value.ToUniversalTime());
        if (request.EndDateTime.HasValue) weatherRegionRelationsQuery = weatherRegionRelationsQuery.Where(x => x.Weather.MeasurementDateTime <= request.EndDateTime.Value.ToUniversalTime());
        if (request.WeatherCondition != null) weatherRegionRelationsQuery = weatherRegionRelationsQuery.Where(x => x.Weather.WeatherCondition == request.WeatherCondition);
        if (request.RegionId != null)
        {
            var regionExists = await _regionRepository.AnyAsync(x => x.Id == request.RegionId, cancellationToken);
            if (regionExists == false) throw new NotFoundException($"Регион с id '{request.RegionId}' не найден");

            weatherRegionRelationsQuery = weatherRegionRelationsQuery.Where(x => x.RegionId == request.RegionId);
        }

        response.Items = await weatherRegionRelationsQuery
            .Include(x => x.Weather).ThenInclude(x => x.Forecasts)
            .Include(x => x.Region)
            .Skip(request.From)
            .Take(request.Size)
            .ProjectTo<SearchWeathersQueryWeatherDto>(_mapper.ConfigurationProvider)
            .ToListAsync(cancellationToken);

        return response;
    }
}